#include "FitnessEvaluator.h"
#include "FitnessEvaluator.h"
#include "math.h"
#include "RandomNumberGenerator.h"
#include "QDebug"

FitnessEvaluator::FitnessEvaluator(float targetValue,int generationLimit)
{
    generation = 0;
    this->targetValue = targetValue;
    this->generationLimit = generationLimit;
    this->finalValue = 0;
}

bool FitnessEvaluator::evaluateFitness(std::vector<Candidate*> population) {
    generation++;
    //qDebug() << generation;
    for(int i=0;i<population.size(); i++) {
       population.at(i)->setFitness(this->getFitness(population.at(i)));
       //if(generation>generationLimit) {
            //population.at(i).data()->setFinalValue(0);
       //}
    }

    if((generation>generationLimit)) {
      qDebug() << "Finished!";
        finalize(returnWinner(population));
        //return true;
        //this->targetValue = RandomNumberGenerator::nextFloat(2000);
        //this->generationLimit = RandomNumberGenerator::nextInt((int)this->generationLimit*0.5) + this->generationLimit*0.75;
        this->generation = 0;
        this->fitness = 0;
        return true;
    } else {
        return false;
    }
    return false;
}
float FitnessEvaluator::getFitness(Candidate* candidate) {

            float value = 0;
            float operatorVal = 0;
            float finalVal = 0;
            for(int i = 0;i<candidate->getLength();i++) {
                if(i == 0 ) {
                    finalVal = candidate->getChromosome(0);
                } else if(i%2 == 0){
                    value = candidate->getChromosome(i);
                    if(operatorVal < 0.2) {
                        finalVal = finalVal+value;
                    } else if(operatorVal < 0.4) {
                        finalVal = finalVal-value;
                    } else if(operatorVal < 0.6) {
                        finalVal = finalVal/value;
                    } else if(operatorVal < 0.8) {
                        finalVal = finalVal/value;
                    } else if(operatorVal <= 1) {
                        finalVal = fmod((float)value,finalVal);
                    }

                } else {
                    operatorVal = (candidate->getChromosome(i));
                }

            }
            float fitness = (fabs(targetValue - finalVal));
            if(this->fitness > fitness) {
                this->fitness = fitness;
            }
            this->finalValue = finalVal;
            candidate->setFinalValue(finalVal);
            //qDebug() << "FinalVal: " << finalVal;
            //qDebug() << "Fitness: " << fitness;
            return fitness;
}

Candidate* FitnessEvaluator::returnWinner(std::vector<Candidate*> population) {
    Candidate* winner;
    winner = population.at(0);
    for(int i = 1;i<population.size();i++) {
        if(population.at(i)->getFitness() > winner->getFitness()) {
            winner = population.at(i);
        }
    }
    return winner;
}

Candidate* FitnessEvaluator::finalize(Candidate* candidate) {

    QString printString;
    QString numString;
    float value = 0;
    float operatorVal = 0;
    float finalVal = 0;
    for(int i = 0;i<candidate->getLength();i++) {
        if(i == 0 ) {
            finalVal = candidate->getChromosome(0);
        } else if(i%2 == 0){
            value = candidate->getChromosome(i);
            if(operatorVal < 0.2) {
                finalVal = finalVal+value;
            } else if(operatorVal < 0.4) {
                finalVal = finalVal-value;
            } else if(operatorVal < 0.6) {
                finalVal = finalVal/value;
            } else if(operatorVal < 0.8) {
                finalVal = finalVal/value;
            } else if(operatorVal <= 1) {
                finalVal = fmod((float)value,finalVal);
            }

        } else {
            operatorVal = (candidate->getChromosome(i));
        }

    }
    float fitness = (fabs(targetValue - finalVal));
    qDebug() << "Generation: " << generation;
    qDebug() << "FinalVal: " << finalVal;
    qDebug() << "Fitness: " << (fitness);
    qDebug() << printString;
    this->finalValue = finalVal;
    return candidate;
}
float FitnessEvaluator::getFinalValue() {
    return finalValue;
}
void FitnessEvaluator::setTargetValue(float targetValue) {
    this->targetValue = targetValue;
}
